﻿using HalconDotNet;
using KstopaCommon;
using System;
using System.Drawing;

namespace HVision
{
    public class HLineGuage : HMetrologyShape
    {
        /// <summary>
        /// 测量起点Col
        /// </summary>
        public double Col1 { get; set; }

        /// <summary>
        /// 测量终点Col
        /// </summary>
        public double Col2 { get; set; }

        /// <summary>
        /// 测量起点Row
        /// </summary>
        public double Row1 { get; set; }

        /// <summary>
        /// 测量终点Row
        /// </summary>
        public double Row2 { get; set; }

        /// <summary>
        /// 测量直线中点Col
        /// </summary>
        public double MidCol { get; private set; }

        /// <summary>
        /// 测量直线中点Row
        /// </summary>
        public double MidRow { get; private set; }

        /// <summary>
        /// 测量直线角度
        /// </summary>
        public double Phi { get; private set; }

        /// <summary>
        /// 测量区域长轴半长
        /// </summary>
        public double Lenght1 { get; private set; }

        private double lenght2;
        /// <summary>
        /// 测量区域短轴半长
        /// </summary>
        public double Lenght2
        {
            get
            {
                lenght2 = CaliperHeight;
                return lenght2;
            }
        }

        public HLineGuage()
        {
            ShapeType = HShapeType.LineGuage;
            numHandles = 5;
            activeHandleIdx = 0;
            HitHandle = HDragHandle.NoHandle;
            Col1 = 100;
            Col2 = 200;
            Row1 = 50;
            Row2 = 50;
            MidCol = 0.5 * (Col1 + Col2);
            MidRow = 0.5 * (Row1 + Row2);
        }

        public override void Measure(HImage image)
        {
            try
            {
                ResultMeasured = new HTuple();
                hMetrology = new HMetrologyModel();
                hContour = null;
                hCross = null;
                hXLDCont = null;
                int width, height;
                image.GetImageSize(out width, out height);
                hMetrology.SetMetrologyModelImageSize(width, height);
                int lineIndex = hMetrology.AddMetrologyObjectLineMeasure(Row1, Col1, Row2, Col2, CaliperHeight, CaliperWidth, MeasureSigma, MeasureThreshold, new HTuple(), new HTuple());
                //设置测量对象的参数
                //Creating measure regions
                if (distOrNum == false)
                {
                    hMetrology.SetMetrologyObjectParam(lineIndex, "measure_distance", MeasureDistance);
                }
                else
                {
                    hMetrology.SetMetrologyObjectParam(lineIndex, "num_measures", CaliperNum);
                }
                //hMetrology.SetMetrologyObjectParam(lineIndex, "measure_length1", caliperHeight);
                //hMetrology.SetMetrologyObjectParam(lineIndex, "measure_length2", caliperWidth);
                //hMetrology.SetMetrologyObjectParam(lineIndex, "measure_distance", measureDistance);

                //Edge detection
                //hMetrology.SetMetrologyObjectParam(lineIndex, "measure_sigma", MeasureSigma);
                //hMetrology.SetMetrologyObjectParam(lineIndex, "measure_threshold", measureThreshold);
                switch (MeasureTransition)
                {
                    case HTransitionType.Bw:
                        hMetrology.SetMetrologyObjectParam(lineIndex, "measure_transition", "positive");
                        break;
                    case HTransitionType.Wb:
                        hMetrology.SetMetrologyObjectParam(lineIndex, "measure_transition", "negative");
                        break;
                    case HTransitionType.All:
                        hMetrology.SetMetrologyObjectParam(lineIndex, "measure_transition", "all");
                        break;
                }
                hMetrology.SetMetrologyObjectParam(lineIndex, "measure_select", MeasureSelect.ToString());
                hMetrology.SetMetrologyObjectParam(lineIndex, "measure_interpolation", MeasureInterpolation.ToString());

                //Fitting the geometric shapes
                hMetrology.SetMetrologyObjectParam(lineIndex, "min_score", MinScore);
                hMetrology.SetMetrologyObjectParam(lineIndex, "num_instances", NumInstances);
                hMetrology.SetMetrologyObjectParam(lineIndex, "distance_threshold", DistanceThreshold);
                hMetrology.SetMetrologyObjectParam(lineIndex, "max_num_iterations", MaxNumIterations);
                hMetrology.SetMetrologyObjectParam(lineIndex, "rand_seed", RandSeed);
                hMetrology.SetMetrologyObjectParam(lineIndex, "instances_outside_measure_regions", InstancesOutsideMeasureRegions == true ? "true" : "false");

                //执行测量,获取边缘点集
                hMetrology.ApplyMetrologyModel(image);
                hXLDCont = hMetrology.GetMetrologyObjectMeasures("all", "all", out PointsMeasuredRows, out PointsMeasuredCols);
                HOperatorSet.GenCrossContourXld(out hCross, PointsMeasuredRows, PointsMeasuredCols, 6, 0.785398);
                //获取最终测量数据和轮廓线
                ResultMeasured = hMetrology.GetMetrologyObjectResult(lineIndex, "all", "result_type", "all_param");
                hContour = hMetrology.GetMetrologyObjectResultContour("all", "all", 1.5);
                hMetrology.ClearMetrologyObject(lineIndex);
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message);
                LogHelper.ErrorLog(exc.Message, null);
            }
        }

        PointD pointA, pointB, point_lowerleft, point_upperleft, point_upperright, point_lowerright, point_lowermid, point_uppermid;
        public override void Draw(HWindow hWindow)
        {
            try
            {
                hWindow.SetLineWidth(2);
                Phi = Math.Atan2(Row2 - Row1, Col2 - Col1);
                Lenght1 = HMisc.DistancePp(Row1, Col1, Row2, Col2) / 2;
                pointA = new PointD(Col1, Row1);
                pointB = new PointD(Col2, Row2);
                point_lowerleft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(pointA, pointB, CaliperHeight);
                point_upperleft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(pointA, pointB, CaliperHeight, false);
                point_upperright = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(pointB, pointA, CaliperHeight);
                point_lowerright = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(pointB, pointA, CaliperHeight, false);
                point_lowermid = new PointD(0.5 * (point_lowerleft.X + point_lowerright.X), 0.5 * (point_lowerleft.Y + point_lowerright.Y));
                point_uppermid = new PointD(0.5 * (point_upperleft.X + point_upperright.X), 0.5 * (point_upperleft.Y + point_upperright.Y));

                PointD center = new PointD(MidCol, MidRow);
                PointD iconLeftMid = CalFormula.GetPointOfExtensionLine(pointA, center, 10);
                PointD iconRightMid = CalFormula.GetPointOfExtensionLine(pointA, center, 10 + 2 * iconWidth);
                PointD iconMid = new PointD(0.5 * (iconLeftMid.X + iconRightMid.X), 0.5 * (iconLeftMid.Y + iconRightMid.Y));
                PointD iconLowerRight, iconUpperRight, iconLowerLeft, iconUpperLeft;
                if (pointB.X >= pointA.X)
                {
                    if (pointB.X >= iconLeftMid.X && pointB.X <= iconRightMid.X)
                    {
                        iconLowerLeft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconLeftMid, pointB, iconHeight);
                        iconUpperLeft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconLeftMid, pointB, iconHeight, false);
                        iconLowerRight = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconRightMid, pointB, iconHeight, false);
                        iconUpperRight = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconRightMid, pointB, iconHeight);
                    }
                    else if (pointB.X <= iconLeftMid.X && pointB.X <= iconRightMid.X)
                    {
                        iconLowerLeft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconLeftMid, pointB, iconHeight, false);
                        iconUpperLeft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconLeftMid, pointB, iconHeight);
                        iconLowerRight = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconRightMid, pointB, iconHeight, false);
                        iconUpperRight = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconRightMid, pointB, iconHeight);
                    }
                    else
                    {
                        iconLowerLeft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconLeftMid, pointB, iconHeight);
                        iconUpperLeft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconLeftMid, pointB, iconHeight, false);
                        iconLowerRight = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconRightMid, pointB, iconHeight);
                        iconUpperRight = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconRightMid, pointB, iconHeight, false);
                    }
                }
                else
                {
                    if (pointB.X >= iconRightMid.X && pointB.X <= iconLeftMid.X)
                    {
                        iconLowerLeft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconLeftMid, pointB, iconHeight);
                        iconUpperLeft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconLeftMid, pointB, iconHeight, false);
                        iconLowerRight = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconRightMid, pointB, iconHeight, false);
                        iconUpperRight = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconRightMid, pointB, iconHeight);
                    }
                    else if (pointB.X <= iconLeftMid.X && pointB.X <= iconRightMid.X)
                    {
                        iconLowerLeft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconLeftMid, pointB, iconHeight);
                        iconUpperLeft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconLeftMid, pointB, iconHeight, false);
                        iconLowerRight = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconRightMid, pointB, iconHeight);
                        iconUpperRight = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconRightMid, pointB, iconHeight, false);
                    }
                    else
                    {
                        iconLowerLeft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconLeftMid, pointB, iconHeight, false);
                        iconUpperLeft = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconLeftMid, pointB, iconHeight);
                        iconLowerRight = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconRightMid, pointB, iconHeight, false);
                        iconUpperRight = CalFormula.GetPointOfVerticalLineInImageCoordinateSystem(iconRightMid, pointB, iconHeight);
                    }
                }
                PointD iconUpperMid = new PointD(0.5 * (iconUpperLeft.X + iconUpperRight.X), 0.5 * (iconUpperLeft.Y + iconUpperRight.Y));
                PointD iconLowerMid = new PointD(0.5 * (iconLowerLeft.X + iconLowerRight.X), 0.5 * (iconLowerLeft.Y + iconLowerRight.Y));

                //画测量线
                hWindow.SetDraw("margin");
                hWindow.SetColor("blue");
                hWindow.DispLine(Row1, Col1, Row2, Col2);

                //画卡尺轮廓
                if (DispPaths && hXLDCont != null)
                {
                    hWindow.SetColor("gray");
                    hWindow.DispXld(hXLDCont);
                }

                //画黑白指向箭头
                hWindow.SetDraw("fill");
                hWindow.SetColor("black");
                hWindow.DispRectangle2(0.5 * (iconUpperMid.Y + iconMid.Y), 0.5 * (iconUpperMid.X + iconMid.X), -Phi, 6, 9);
                hWindow.SetColor("white");
                hWindow.DispRectangle2(0.5 * (iconLowerMid.Y + iconMid.Y), 0.5 * (iconLowerMid.X + iconMid.X), -Phi, 6, 9);
                PointD triangleLeft, triangleRight, triangleMid;
                HRegion hRegion = null;
                HTuple rows = new HTuple(), cols = new HTuple();
                switch (MeasureTransition)//20*60,10
                {
                    case HTransitionType.Bw:
                        hRegion = new HRegion();
                        triangleLeft = new PointD((2 * iconUpperLeft.X + iconLowerLeft.X) / 3, (2 * iconUpperLeft.Y + iconLowerLeft.Y) / 3);
                        triangleRight = new PointD((2 * iconUpperRight.X + iconLowerRight.X) / 3, (2 * iconUpperRight.Y + iconLowerRight.Y) / 3);
                        triangleMid = new PointD((iconUpperMid.X + 2 * iconLowerMid.X) / 3, (iconUpperMid.Y + 2 * iconLowerMid.Y) / 3);
                        rows.Append(triangleLeft.Y);
                        rows.Append(triangleMid.Y);
                        rows.Append(triangleRight.Y);
                        rows.Append(triangleLeft.Y);
                        cols.Append(triangleLeft.X);
                        cols.Append(triangleMid.X);
                        cols.Append(triangleRight.X);
                        cols.Append(triangleLeft.X);
                        hRegion.GenRegionPolygonFilled(rows, cols);
                        hWindow.SetColor(new HTuple("#7F7F7F"));
                        hWindow.DispObj(hRegion);
                        break;
                    case HTransitionType.Wb:
                        hRegion = new HRegion();
                        triangleLeft = new PointD((iconUpperLeft.X + 2 * iconLowerLeft.X) / 3, (iconUpperLeft.Y + 2 * iconLowerLeft.Y) / 3);
                        triangleRight = new PointD((iconUpperRight.X + 2 * iconLowerRight.X) / 3, (iconUpperRight.Y + 2 * iconLowerRight.Y) / 3);
                        triangleMid = new PointD((2 * iconUpperMid.X + iconLowerMid.X) / 3, (2 * iconUpperMid.Y + iconLowerMid.Y) / 3);
                        rows.Append(triangleLeft.Y);
                        rows.Append(triangleMid.Y);
                        rows.Append(triangleRight.Y);
                        rows.Append(triangleLeft.Y);
                        cols.Append(triangleLeft.X);
                        cols.Append(triangleMid.X);
                        cols.Append(triangleRight.X);
                        cols.Append(triangleLeft.X);
                        hRegion.GenRegionPolygonFilled(rows, cols);
                        hWindow.SetColor(new HTuple("#7F7F7F"));
                        hWindow.DispObj(hRegion);
                        break;
                    case HTransitionType.All:
                    default:
                        break;
                }
                hWindow.SetDraw("margin");
                hWindow.SetColor("blue");
                hWindow.DispLine(iconLowerLeft.Y, iconLowerLeft.X, iconUpperLeft.Y, iconUpperLeft.X);
                hWindow.DispLine(iconLowerLeft.Y, iconLowerLeft.X, iconLowerRight.Y, iconLowerRight.X);
                hWindow.DispLine(iconLowerRight.Y, iconLowerRight.X, iconUpperRight.Y, iconUpperRight.X);
                hWindow.DispLine(iconUpperRight.Y, iconUpperRight.X, iconUpperLeft.Y, iconUpperLeft.X);

                //画测量区域外框
                hWindow.SetColor("blue");
                hWindow.DispLine(Row1, Col1, Row2, Col2);
                hWindow.DispLine(point_lowerleft.Y, point_lowerleft.X, point_upperleft.Y, point_upperleft.X);
                hWindow.DispLine(point_lowerleft.Y, point_lowerleft.X, point_lowerright.Y, point_lowerright.X);
                hWindow.DispLine(point_lowerright.Y, point_lowerright.X, point_upperright.Y, point_upperright.X);
                hWindow.DispLine(point_upperright.Y, point_upperright.X, point_upperleft.Y, point_upperleft.X);
                //hWindow.DispRectangle2(MidRow, MidCol, -phi, lenght1, Lenght2);
                hWindow.SetDraw("fill");
                hWindow.SetColor("white");
                hWindow.DispRectangle2(MidRow, MidCol, 0, unitSize, unitSize);
                hWindow.DispCircle(Row1, Col1, unitSize);
                hWindow.DispCircle(Row2, Col2, unitSize);
                hWindow.SetColor("black");
                hWindow.DispCircle(point_lowermid.Y, point_lowermid.X, unitSize);
                hWindow.DispCircle(point_uppermid.Y, point_uppermid.X, unitSize);
                hWindow.SetDraw("margin");
                hWindow.SetColor("blue");
                hWindow.DispRectangle2(MidRow, MidCol, 0, unitSize, unitSize);
                hWindow.DispCircle(Row1, Col1, unitSize);
                hWindow.DispCircle(Row2, Col2, unitSize);
                hWindow.DispCircle(point_lowermid.Y, point_lowermid.X, unitSize);
                hWindow.DispCircle(point_uppermid.Y, point_uppermid.X, unitSize);

                //画叉点
                if (DispPoints && hCross != null)
                {
                    hWindow.SetColor("green");
                    hWindow.DispObj(hCross);
                }

                //画实际测量直线
                if (hContour != null)
                {
                    hWindow.SetColor("green");
                    hWindow.DispXld(hContour);
                }
            }
            catch (Exception exc)
            {
                LogHelper.ErrorLog(exc.Message, null);
            }
        }

        /// <summary> 
		/// Returns the distance of the LineGuage handle being
		/// closest to the image point(x,y)
		/// </summary>
		/// <param name="x">x (=column) coordinate</param>
		/// <param name="y">y (=row) coordinate</param>
		/// <returns> 
		/// Distance of the closest LineGuage handle.
		/// </returns>
		public override double DistToClosestHandle(double x, double y)
        {
            double max = 10000;
            double[] val = new double[numHandles];
            val[0] = HMisc.DistancePp(y, x, Row1, Col1);
            val[1] = HMisc.DistancePp(y, x, Row2, Col2);
            val[2] = HMisc.DistancePp(y, x, MidRow, MidCol);
            val[3] = HMisc.DistancePp(y, x, point_lowermid.Y, point_lowermid.X);
            val[4] = HMisc.DistancePp(y, x, point_uppermid.Y, point_uppermid.X);

            for (int i = 0; i < numHandles; i++)
            {
                if (val[i] < max)
                {
                    max = val[i];
                    activeHandleIdx = i;
                }
            }

            return val[activeHandleIdx];
        }

        public override void MoveByHandle(double x, double y)
        {
            switch (activeHandleIdx)
            {
                case 0: // start
                    Row1 = y;
                    Col1 = x;
                    break;
                case 1: // end
                    Row2 = y;
                    Col2 = x;
                    break;
                case 2: // mid 
                    Col1 += x - MidCol;
                    Row1 += y - MidRow;
                    Col2 += x - MidCol;
                    Row2 += y - MidRow;
                    break;
                case 3: // lower mid
                    CaliperHeight = HMisc.DistancePl(y, x, Row1, Col1, Row2, Col2);
                    break;
                case 4: // upper mid
                    CaliperHeight = HMisc.DistancePl(y, x, Row1, Col1, Row2, Col2);
                    break;
            }
            MidCol = 0.5 * (Col1 + Col2);
            MidRow = 0.5 * (Row1 + Row2);
        }

        public override HRegion GetRegion()
        {
            return null;
        }

        public void Draw(Graphics graphics, Color color)
        {
            Pen pen = new Pen(color);
            graphics.DrawLine(pen, new Point((int)Col1 + unitSize, (int)Row1), new Point((int)MidCol - unitSize, (int)Row2));
            graphics.DrawLine(pen, new Point((int)MidCol + unitSize, (int)Row1), new Point((int)Col2 - unitSize, (int)Row2));
            graphics.DrawRectangle(pen, new Rectangle((int)MidCol - unitSize, (int)MidRow - unitSize, 2 * unitSize, 2 * unitSize));
            graphics.DrawEllipse(pen, new Rectangle((int)Col1 - unitSize, (int)Row1 - unitSize, 2 * unitSize, 2 * unitSize));
            graphics.DrawEllipse(pen, new Rectangle((int)Col2 - unitSize, (int)Row2 - unitSize, 2 * unitSize, 2 * unitSize));

            graphics.DrawLine(pen, new Point((int)Col1, (int)Row1 - unitSize), new Point((int)Col1, (int)(Row1 - CaliperHeight)));
            graphics.DrawLine(pen, new Point((int)Col1, (int)Row1 + unitSize), new Point((int)Col1, (int)(Row1 + CaliperHeight)));
            graphics.DrawLine(pen, new Point((int)Col2, (int)Row2 - unitSize), new Point((int)Col2, (int)(Row2 - CaliperHeight)));
            graphics.DrawLine(pen, new Point((int)Col2, (int)Row2 + unitSize), new Point((int)Col2, (int)(Row2 + CaliperHeight)));

            graphics.DrawLine(pen, new Point((int)Col1, (int)(Row1 - CaliperHeight)), new Point((int)MidCol - unitSize, (int)(Row1 - CaliperHeight)));
            graphics.DrawLine(pen, new Point((int)MidCol + unitSize, (int)(Row1 - CaliperHeight)), new Point((int)Col2, (int)(Row1 - CaliperHeight)));
            graphics.DrawEllipse(pen, new Rectangle((int)MidCol - unitSize, (int)(MidRow - CaliperHeight - unitSize), 2 * unitSize, 2 * unitSize));

            graphics.DrawLine(pen, new Point((int)Col1, (int)(Row1 + CaliperHeight)), new Point((int)MidCol - unitSize, (int)(Row1 + CaliperHeight)));
            graphics.DrawLine(pen, new Point((int)MidCol + unitSize, (int)(Row1 + CaliperHeight)), new Point((int)Col2, (int)(Row1 + CaliperHeight)));
            graphics.DrawEllipse(pen, new Rectangle((int)MidCol - unitSize, (int)(MidRow + CaliperHeight - unitSize), 2 * unitSize, 2 * unitSize));
        }

    }

}
